package org.example.com.editor.workspace;


import org.example.com.editor.exception.UnSavedModificationException;
import org.example.com.editor.editor.TextEditor;
import org.example.com.editor.editor.Editor;
import org.example.com.editor.io.FileIOUtil;
import org.example.com.editor.logger.LogManager;
import org.example.com.editor.util.JacksonWorkspaceSerializer;
import org.example.com.editor.util.WorkspaceSerializer;

import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

public class Workspace {
    private final WorkspaceManager stateManager;
    private final Map<String, Editor> openedFiles ;
    private String activeFilePath;
    private final LogManager logManager;

    public Workspace(LogManager logManager){
        this.logManager = logManager;
        WorkspaceSerializer jacksonSerializer = new JacksonWorkspaceSerializer();
        stateManager = new WorkspaceManager(jacksonSerializer);
      openedFiles = new LinkedHashMap<>(16, 0.75f, true);
        try {
            loadState();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public void loadFile(String filePath) throws IOException {
        filePath = toCanonicalPath(filePath);
        if (openedFiles.containsKey(filePath)) {
            openedFiles.get(filePath); // 访问以更新顺序
            activeFilePath = filePath;
            return;
        }

        File file = new File(filePath);
        if(!file.exists()){
            boolean createSuccess; // 在磁盘创建空文件
            try {
                createSuccess = file.createNewFile();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            if (!createSuccess) {
                throw new IOException("创建新文件失败：" + filePath + "（可能权限不足）");
            }
            Editor editor = new TextEditor(filePath, new ArrayList<>(),true);
            openedFiles.put(filePath, editor);
        }else{
            List<String> content = FileIOUtil.readFile(filePath);
            Editor editor = new TextEditor(filePath, content,false);
            openedFiles.put(filePath, editor);
        }
        activeFilePath = filePath;
    }

    public void closeFile(String filePath,boolean force) throws IOException {
        filePath = toCanonicalPath(filePath);
        if(!openedFiles.containsKey(filePath)) {
            throw new IllegalArgumentException("文件未打开，无法关闭：" + filePath);
        }else if(openedFiles.get(filePath).isModified()&&!force){
            throw new UnSavedModificationException("文件有未保存的修改，是否保存后关闭？(y/n)：" + filePath);
        }else{
            openedFiles.remove(filePath);
            if (filePath.equals(activeFilePath)) {
                if (openedFiles.isEmpty()) {
                    activeFilePath = null;
                } else {
                    Set<String> FileNames = openedFiles.keySet();
                    List<String> FileNameList = new ArrayList<>(FileNames);
                    activeFilePath = FileNameList.get(FileNameList.size() - 1);
                }
            }
        }
    }

    public void saveFile(String filePath) throws IOException {
        filePath = toCanonicalPath(filePath);
        if (!openedFiles.containsKey(filePath)) {
            throw new IllegalArgumentException("文件未打开，无法保存：" + filePath);
        }
        List<String> content = openedFiles.get(filePath).getContent();
        FileIOUtil.writeFile(filePath, content);
        openedFiles.get(filePath).setModified(false);
        System.out.println("已保存：" + filePath);
    }

    public void saveFile() throws IOException {
        if (activeFilePath == null || !openedFiles.containsKey(activeFilePath)) {
            throw new IllegalArgumentException("无活动文件可保存");
        }
        saveFile(activeFilePath);
    }


    public void editFile(String filePath) throws IOException {
        filePath = toCanonicalPath(filePath);
        if (!openedFiles.containsKey(filePath)) {
            throw new IllegalArgumentException("文件未打开，无法编辑：" + filePath);
        }
        //此处仅用于更新访问记录
        openedFiles.get(filePath);
        activeFilePath = filePath;
    }

    public void initFile(String filePath, boolean withLog) {
        File bufferFile = new File(filePath.trim());
        filePath = bufferFile.getAbsolutePath();
        if (openedFiles.containsKey(filePath)) {
            throw new IllegalArgumentException("文件已在工作区打开，无法重复初始化：" + filePath);
        }

        File diskFile = new File(filePath);
        if (diskFile.exists()) {
            throw new IllegalArgumentException("文件已存在于磁盘，无法初始化：" + filePath);
        }

        List<String> initContent = new ArrayList<>();
        if (withLog) {
            initContent.add("# log"); // 带with-log时，首行添加日志标记
        }

        // 4. 创建FileState：标记为已修改（新缓冲文件默认需保存）
        Editor newEditor = new TextEditor(filePath, initContent, true);

        // 5. 加入工作区已打开文件列表，并设为当前活动文件
        openedFiles.put(filePath, newEditor);
        activeFilePath = filePath;
    }

    public List<String> getOpenedFiles() {
        return new ArrayList<>(openedFiles.keySet());
    }

    public String getActiveFile() {
        return activeFilePath;
    }

    public boolean isFileModified(String filePath) throws IOException{
        filePath = toCanonicalPath(filePath);
        return openedFiles.get(filePath).isModified();
    }


    public void saveState () throws IOException {
            // 1. 原发器创建备忘录
            WorkspaceState memento = new WorkspaceState(
                    new ArrayList<>(openedFiles.keySet()),
                    activeFilePath,
                    openedFiles.entrySet().stream().collect(Collectors.toMap(
                            Map.Entry::getKey,
                            entry -> entry.getValue().isModified()
                    )),
                    new HashMap<>(logManager.getLogEnabledMap())
            );
            stateManager.saveMemento(memento);
    }

    public void loadState() throws IOException {
            WorkspaceState memento = stateManager.loadMemento();
            if (memento == null) return;
            for (String path : memento.getOpenedFilePaths()) {
                loadFile(path);
                openedFiles.get(path).setModified(memento.getModifiedStates().get(path));
            }
            this.activeFilePath = memento.getActiveFilePath();
         if (memento.getLogEnabledStates() != null) {
            logManager.getLogEnabledMap().putAll(memento.getLogEnabledStates());
        }
    }

    public Editor getActiveEditor(){
        if(activeFilePath==null){
            throw new IllegalArgumentException("无活动文件");
        }
        return openedFiles.get(activeFilePath);
    }

    private String toCanonicalPath(String inputPath) throws IOException {
        // 用File.getCanonicalPath()：自动处理相对→绝对、符号链接、../等，确保唯一性
        File file = new File(inputPath.trim());
        return file.getCanonicalPath();
    }

}
